package com.zyh.scs.admin.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.zyh.scs.admin.api.bo.NotifyBo;
import com.zyh.scs.admin.api.dto.open.CallbackDTO;
import com.zyh.scs.admin.api.entity.QrCodeUsage;
import com.zyh.scs.admin.api.entity.UserCation;
import com.zyh.scs.admin.mapper.UserCationMapper;
import com.zyh.scs.admin.service.QrCodeUsageService;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;

import static dm.jdbc.desc.Configuration.url;

/**
 * 满客宝回调
 *
 * @author hwh
 */
@Slf4j
@Component
public class OtherThingHelper {

    protected static ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper();
        OBJECT_MAPPER.registerModule(new JavaTimeModule());
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //允许json中包含转义符
        OBJECT_MAPPER.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
    }

    @Resource
    private QrCodeUsageService qrCodeUsageService;
    @Resource
    private UserCationMapper userCationMapper;
    @Value("${goodShop.notifyUrl}")
    private String goodShopNotifyUrl;
    @Resource
    private RedissonClient redissonClient;

    private static final String USER_CATION_KEY = "USER_CATION_KEY";

    @Async
    @SneakyThrows
    public void callback(CallbackDTO param, String merchantId) {
        UserCation userCation = getRedisCation(merchantId);

        if (userCation == null) {
            log.info("该商户号不存在，merchant:{}", merchantId);
            return;
        }

        if (StrUtil.isNotBlank(userCation.getMerchantId())) {
            log.info("该商户号无回调地址，merchant:{},url:{}", merchantId, url);
            return;
        }

        String url = userCation.getCallbackUrl();
        log.info("merchant:{},url:{}", merchantId, url);
        //10秒超时
        final HttpResponse res = HttpRequest.post(url).timeout(10000).body(OBJECT_MAPPER.writeValueAsString(param)).execute();
        final String body = res.body();
        log.info("回调结果：{}", body);
        final JsonNode jsonNode = OBJECT_MAPPER.readTree(body);
        final int errCode = jsonNode.get("errCode").asInt();
        if (errCode != 100000) {
            throw new RuntimeException("回调失败");
        }
    }

    public UserCation getRedisCation(String merchantId) {
        // TODO 加缓存 UserCation
        RBucket<UserCation> bucket = redissonClient.getBucket(USER_CATION_KEY + merchantId);
        UserCation userCation = new UserCation();
        if (bucket.isExists()) {
            userCation = bucket.get();
        } else {
            //缓存没有 存入redis中
            userCation = userCationMapper
                    .selectOne(Wrappers.<UserCation>lambdaQuery()
                            .eq(UserCation::getMerchantId, merchantId));

            bucket.set(userCation);
        }
        return userCation;
    }

    /**
     * 消费用户ID、消费时间、消费金额、订单号
     *
     * @param notifyBo
     */
    @Async
    @Retryable(value = {Exception.class, Error.class}, backoff = @Backoff(delay = 3000, multiplier = 3))
    @SneakyThrows
    public void notifyGoodShop(NotifyBo notifyBo) {
        if (!StringUtils.hasText(notifyBo.getOperQrCode())) {
            return;
        }
        final boolean isGoodShop = notifyBo.getOperQrCode().contains("#GDSH#");
        //轨道生活通通知
        if (isGoodShop) {
            try (final HttpResponse execute = HttpRequest.post(goodShopNotifyUrl)
                    .body(OBJECT_MAPPER.writeValueAsString(notifyBo))
                    .execute()) {
                final String body = execute.body();
                log.info("通知结果：{}", body);
            } catch (Exception e) {
                log.error("通知好店失败：{}", notifyBo, e);
                throw e;
            }
        }
        //避免重复保存
        if (qrCodeUsageService.lambdaQuery()
                .eq(QrCodeUsage::getOperQrCode, notifyBo.getOperQrCode())
                .eq(QrCodeUsage::getDeleted, Boolean.FALSE).count() > 0) {
            return;
        }
        QrCodeUsage qrCodeUsage = new QrCodeUsage();
        //qrCodeUsage.setId();
        qrCodeUsage.setGuid(notifyBo.getGuid());
        qrCodeUsage.setOperQrCode(notifyBo.getOperQrCode());
        qrCodeUsage.setAmount(notifyBo.getAmount());
        qrCodeUsage.setUseTime(notifyBo.getUseTime());
        qrCodeUsage.setIsGoodShop(isGoodShop);
        qrCodeUsage.setCreateTime(LocalDateTime.now());
        qrCodeUsage.setCreateBy(notifyBo.getGuid());
        qrCodeUsage.setModifyTime(LocalDateTime.now());
        qrCodeUsage.setModifyBy(notifyBo.getGuid());
        qrCodeUsage.setDeleted(Boolean.FALSE);
        qrCodeUsageService.save(qrCodeUsage);
    }
}